<?php
require_once('pworks/common/dao/DBConfig.class.php');
abstract class DaoFactory {
    private static $_doSQLTotal = array();
    
    private static $_log = null;
    
    public static function getDao($table, $dbConfigKey="default") {
        //get a pdo instance by the token and key
        $daoClz = DBConfig::getDAOClass($table);
        //var_dump($daoClz);
        $dao = null;
        if($daoClz){
            $dao = new $daoClz();
        }else{
            $dao = new Dao();
        }
        $dao->setTable($table);
        $dao->setDBConfigKey($dbConfigKey);
        $dao->init();
        //var_dump($dao);exit;
        return $dao; 
    }
    public static function toLog($msg) {
        if (!self::$_log) {
            //$logFile = dirname(__FILE__) . "/log/Dao.log";
            //self::$_log = fopen($logFile, "a");
        }
        //fwrite(self::$_log, $msg);
    }
    public static function addQuery($type, $sql) {
        if ($type == "query") {
            self::$_doSQLTotal["query"]++;
            if (preg_match("/[^a-z]like[^a-z]/i", $sql)) {
                self::$_doSQLTotal["like"]++;
            }
        } elseif ($type == "delect") {
            self::$_doSQLTotal["delect"]++;
        } elseif ($type == "insert") {
            self::$_doSQLTotal["insert"]++;
        } elseif ($type == "update") {
            self::$_doSQLTotal["update"]++;
        }
    }
    public static function getQueryTotal() {
        return self::$_doSQLTotal;
    }
}
class BaseDao {
    private static $_pdos = null;
    protected function getPdo($dbConfigKey) {
        $existsToken = DBConfig::existsToken($dbConfigKey);
        //var_dump($existsToken);
        if ($existsToken) {
            if (!self::$_pdos[$dbConfigKey]["MASTER"]) {
                $dbConfig = DBConfig::getDBConfig($dbConfigKey, "MASTER");
                //var_dump($dbConfig);
                self::$_pdos[$dbConfigKey]["MASTER"] = new PDO('mysql:host='.$dbConfig["DB_HOST"].';dbname='.$dbConfig["DB_NAME"], $dbConfig["DB_USER"], $dbConfig["DB_PSW"]);
                self::$_pdos[$dbConfigKey]["MASTER"]->exec("set names 'utf8'");
            }
            return self::$_pdos[$dbConfigKey]["MASTER"];
        } else {
            if (!self::$_pdos[$dbConfigKey]["SLAVE"]) {
                $dbConfig = DBConfig::getDBConfig($dbConfigKey, "SLAVE");
                //var_dump($dbConfig);
                self::$_pdos[$dbConfigKey]["SLAVE"] = new PDO('mysql:host='.$dbConfig["DB_HOST"].';dbname='.$dbConfig["DB_NAME"], $dbConfig["DB_USER"], $dbConfig["DB_PSW"]);
                self::$_pdos[$dbConfigKey]["SLAVE"]->exec("set names 'utf8'");
            }
            return self::$_pdos[$dbConfigKey]["SLAVE"];
        }
    }
}

class Dao extends BaseDao {
    private $_fields;
    private $_primary;
    private $_table;
    private $_valueClass;
    private $_dbConfigKey;
    public function __construct() {
    }
    public function setTable($table) {
        $this->_table = $table;
    }
    public function setDBConfigKey($dbConfigKey) {
        $this->_dbConfigKey = $dbConfigKey;
    }
    public function init() {
        $statement = $this->query("describe {$this->_table}");
            if (!$statement) {
                var_dump("describe {$this->_table}");
                var_dump($this->getPdo($this->_dbConfigKey)->errorInfo());
                return false;
            }
        $fields = $statement->fetchAll(PDO::FETCH_ASSOC);
        $statement->closeCursor();
        $this->_fields = array();
        foreach ($fields as $field) {
            if (!$this->_primary && $field["Key"] == "PRI") {
                $this->_primary = $field["Field"];
            }
            $this->_fields[] = $field["Field"];
        }
        $this->_valueClass = str_replace(" ", "", ucwords(str_replace("_", " ", $this->_table)));
        $classFile = DAO_VOCLASS_PATH."/value/{$this->_valueClass}Value.class.php";
        if (file_exists($classFile)) {
            require_once($classFile);
        }
    }
    
    
    protected function query($sql) {
        //var_dump(DBConfig::existsToken($this->_dbConfigKey));
        DaoFactory::toLog($sql . "\n");
        if (preg_match("/[^a-z]insert[^a-z]/i", $sql)) {
            echo "Sql have insert.";
            exit;
        }
        
        if (preg_match("/[^a-z]update[^a-z]/i", $sql)) {
            echo "Sql have update.";
            exit;
        }
        
        if (preg_match("/[^a-z]delete[^a-z]/i", $sql)) {
            echo "Sql have delete.";
            exit;
        }
        
        if (preg_match("/[^a-z]replace[^a-z]/i", $sql)) {
            echo "Sql have replace.";
            exit;
        }
        
        $statement = $this->getPdo($this->_dbConfigKey)->query($sql);
            if (!$statement) {
                var_dump($sql);
                var_dump($this->getPdo($this->_dbConfigKey)->errorInfo());
                return false;
            }
            DaoFactory::addQuery("query", $sql);
        return $statement;
    }
    
    private function _genSql($where) {
        $fieldsStr = implode(",", $this->_fields);
        return "select {$fieldsStr} from {$this->_table} where {$where}";
    }
    
    public function fetch($where) {
        $sql = $this->_genSql($where);
        DaoFactory::toLog($sql . "\n");
        $statement = $this->query($sql);
            if (!$statement) {
                var_dump($sql);
                var_dump($this->getPdo($this->_dbConfigKey)->errorInfo());
                return false;
            }
        $className = "Value";
        if (class_exists($this->_valueClass)) {
            $className = $this->_valueClass;
        }
        $statement->setFetchMode(PDO::FETCH_CLASS, $className);
        $value = $statement->fetch();
        $statement->closeCursor();
        if (!$value) {
            return false;
        }
        $value->setTable($this->_table);
        $value->setFields($this->_fields);
        $value->setPrimary($this->_primary);
        $value->setDBConfigKey($this->_dbConfigKey);
        return $value;
    }
    public function fetchAll($where) {
        $sql = $this->_genSql($where);
        DaoFactory::toLog($sql . "\n");
        $statement = $this->query($sql);
            if (!$statement) {
                var_dump($sql);
                var_dump($this->getPdo($this->_dbConfigKey)->errorInfo());
                return false;
            }
        $className = "Value";
        if (class_exists($this->_valueClass)) {
            $className = $this->_valueClass;
        }
        $statement->setFetchMode(PDO::FETCH_CLASS, $className);
        $valueArray = $statement->fetchAll();
        $statement->closeCursor();
        $returnArray = array();
        foreach ($valueArray as $value) {
            $value->setTable($this->_table);
            $value->setFields($this->_fields);
            $value->setPrimary($this->_primary);
            $value->setDBConfigKey($this->_dbConfigKey);
            $returnArray[] = $value;
        }
        return $returnArray;
    }
    public function fetchAllPage($where, $page, $pagesize) {
        $rowCount = $this->getRowCount($where);
        $pageCount = ceil($rowCount/$pagesize);
        $startRow = ($page-1)*$pagesize;
        $where .= " limit {$startRow}, {$pagesize}";
        $data = $this->fetchAll($where);
        $returnArray = array();
        $returnArray["page"] = $page;
        $returnArray["pagesize"] = $pagesize;
        $returnArray["pageCount"] = $pageCount;
        $returnArray["rowCount"] = $rowCount;
        //$returnArray['pages'] = ($pageCount > 1) ? range(1, $pageCount) : array(1);
        $returnArray["data"] = $data;
        return $returnArray;
    }
    public function getRowCount($where) {
        $sql = "select count(1) from {$this->_table} where {$where}";
        $statement = $this->query($sql);
            if (!$statement) {
                var_dump($sql);
                var_dump($this->getPdo($this->_dbConfigKey)->errorInfo());
                return false;
            }
        $rowCount = $statement->fetchColumn();
        $statement->closeCursor();
        return $rowCount;
    }
    public function getEmptyValue() {
        $className = "Value";
        if (class_exists($this->_valueClass)) {
            $className = $this->_valueClass;
        }
        $value = new $className();
        $value->setTable($this->_table);
        $value->setFields($this->_fields);
        $value->setPrimary($this->_primary);
        $value->setDBConfigKey($this->_dbConfigKey);
        
        return $value;
    }
    public function getByPrimary($value) {
        $where = "{$this->_primary}='{$value}'";
        return $this->fetch($where);
    }
}
class Value extends BaseDao {
    private $_table;
    private $_fields;
    private $_primary;
    private $_dbConfigKey;
    public function setTable($table) {
        $this->_table = $table;
    }
    public function setFields($fields) {
        $this->_fields = $fields;
    }
    public function setPrimary($primary) {
        $this->_primary = $primary;
    }
    public function setDBConfigKey($dbConfigKey) {
        $this->_dbConfigKey = $dbConfigKey;
    }
    
    public function remove() {
        DBConfig::setToken($this->_dbConfigKey);
        $primaryValue = $this->getPdo($this->_dbConfigKey)->quote($this->{$this->_primary});
        $sql = "delete from {$this->_table} where {$this->_primary}={$primaryValue}";
        DaoFactory::toLog($sql . "\n");
        $result = $this->getPdo($this->_dbConfigKey)->exec($sql);
            if ($result === false) {
                var_dump($sql);
                var_dump($this->getPdo($this->_dbConfigKey)->errorInfo());
                return false;
            }
            DaoFactory::addQuery("delete", $sql);
        return $result;
    }
    
    public function save() {
        DBConfig::setToken($this->_dbConfigKey);
        if ($this->{$this->_primary}) {
            return $this->_update();
        }
        return $this->_insert();
    }
    
    private function _update() {
        $fieldArray = $this->_fields;
        $fieldSetArray = array();
        foreach ($fieldArray as $key=>$fieldName) {
          if (($this->{$fieldName} === null) || ($fieldName == $this->_primary)) {
            unset($fieldArray[$key]);
            continue;
          }
          $fieldSetArray[] = "{$fieldName}=".$this->getPdo($this->_dbConfigKey)->quote($this->{$fieldName});
        }
        $fieldSetString = implode(',', $fieldSetArray);
        $primaryValue = $this->{$this->_primary};
        $whereClause = "{$this->_primary} = {$primaryValue}";
        $sql = "update {$this->_table} set {$fieldSetString} where {$whereClause} limit 1";
        //var_dump($sql);exit;
        DaoFactory::toLog($sql . "\n");
        $result = $this->getPdo($this->_dbConfigKey)->exec($sql);
            if ($result === false) {
                var_dump($sql);
                var_dump($this->getPdo($this->_dbConfigKey)->errorInfo());
                return false;
            }
            DaoFactory::addQuery("update", $sql);
        return $result;
    }
    private function _insert() {
        $fieldArray = $this->_fields;
        $valueArray = array();
        foreach ($fieldArray as $key=>$fieldName) {
          if (($this->$fieldName === null) || ($fieldName == $this->_primary)) {
            unset($fieldArray[$key]);
            continue;
          }
          $valueArray[$key] = $this->getPdo($this->_dbConfigKey)->quote($this->{$fieldName});
        }
        $fieldString = implode(',', $fieldArray);
        $valueString = implode(',', $valueArray);
        $sql = "insert into {$this->_table} ($fieldString) values ($valueString)";
        DaoFactory::toLog($sql . "\n");
        $result = $this->getPdo($this->_dbConfigKey)->exec($sql);
            if ($result === false) {
                var_dump($sql);
                var_dump($this->getPdo($this->_dbConfigKey)->errorInfo());
                return false;
            }
            DaoFactory::addQuery("insert", $sql);
        $primaryValue = $this->getPdo($this->_dbConfigKey)->lastInsertId();
        
        DaoFactory::toLog($primaryValue . "\n");
        $this->{$this->_primary} = $primaryValue;
        return $primaryValue;
    }
}
